package com.fankui.crowd.util;

import com.aliyun.api.gateway.demo.util.HttpUtils;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.comm.ResponseMessage;
import com.aliyun.oss.model.PutObjectResult;
import com.fankui.crowd.constant.CrowdConstant;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * ClassName CrowdUtil
 * Description TODO
 * Date 2023/7/28 16:47
 *
 * @Author 范奎
 * @Since JDK 11
 */
public class CrowdUtil {

    /**
     * 判断当前请求是否为Ajax请求
     *
     * @param request
     * @return true: 是  false: 否
     */
    public static boolean judgeRequestType(HttpServletRequest request) {
        String accept = request.getHeader("Accept");
        String xRequested = request.getHeader("X-Requested-With");
        return (accept != null && accept.contains("application/json") || (xRequested != null && xRequested.equals("XMLHttpRequest")));
    }

    /**
     * 对明文字符串进行MD5加密
     *
     * @param source 传入的明文字符串
     * @return 加密结果
     */
    public static String md5(String source) {
        // 1 判断source是否有效
        if (source == null || source.length() == 0) {
            // 2 如果不是有效的字符串抛出异常
            throw new RuntimeException(CrowdConstant.MESSAGE_STRING_INVALIDATE);
        }

        try {
            // 3 获取MessageDigest对象
            String algorithm = "md5";
            MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
            // 4 获取明文字符串对应的字节数组
            byte[] input = source.getBytes();
            // 5 执行加密
            byte[] output = messageDigest.digest(input);
            // 6 创建BigInteger对象
            int signum = 1;
            BigInteger bigInteger = new BigInteger(signum, output);
            // 7 按照16进制将BigInteger的值转换为字符串
            int radix = 16;
            String encoded = bigInteger.toString(radix).toUpperCase();
            return encoded;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

//    /**
//     * @param secretId  云市场分配的密钥Id   AKIDo681hQxDm6p1I43fg188tNiNSIKg8VPwVJuD
//     * @param secretKey 云市场分配的密钥Key a7Ltv2I4wI7rtXVz48Jj39e9ijlBEM2aBX9Ys9j1
//     * @param content   短信签名和模板需要联系服务商报备开通
//     * @param mobile    短信接收人号码
//     * @return
//     * @throws NoSuchAlgorithmException
//     * @throws InvalidKeyException
//     * @throws UnsupportedEncodingException
//     */
//    public static ResultEntity<String> sendCodeByShortMessage(String secretId, String secretKey, String content, String mobile) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
//        String source = "market";
//
//        Calendar cd = Calendar.getInstance();
//        SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
//        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
//        String datetime = sdf.format(cd.getTime());
//        // 签名
//        String auth = calcAuthorization(source, secretId, secretKey, datetime);
//        // 请求方法
//        String method = "POST";
//        // 请求头
//        Map<String, String> headers = new HashMap();
//        headers.put("X-Source", source);
//        headers.put("X-Date", datetime);
//        headers.put("Authorization", auth);
//
//        // 查询参数
//        Map<String, String> queryParams = new HashMap();
//        queryParams.put("content", content);
//        queryParams.put("mobile", mobile);
//        // body参数
//        Map<String, String> bodyParams = new HashMap();
//
//        // url参数拼接
//        String url = "https://service-4z111o3q-1258291108.gz.apigw.tencentcs.com/release/sms02";
//        if (!queryParams.isEmpty()) {
//            url += "?" + urlencode(queryParams);
//        }
//
//        BufferedReader in = null;
//        try {
//            URL realUrl = new URL(url);
//            HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
//            conn.setConnectTimeout(5000);
//            conn.setReadTimeout(5000);
//            conn.setRequestMethod(method);
//
//            // request headers
//            for (Map.Entry<String, String> entry : headers.entrySet()) {
//                conn.setRequestProperty(entry.getKey(), entry.getValue());
//            }
//
//            // request body
//            Map<String, Boolean> methods = new HashMap<>();
//            methods.put("POST", true);
//            methods.put("PUT", true);
//            methods.put("PATCH", true);
//            Boolean hasBody = methods.get(method);
//            if (hasBody != null) {
//                conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
//
//                conn.setDoOutput(true);
//                DataOutputStream out = new DataOutputStream(conn.getOutputStream());
//                out.writeBytes(urlencode(bodyParams));
//                out.flush();
//                out.close();
//            }
//
//            // 定义 BufferedReader输入流来读取URL的响应
//            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
//            String line;
//            String result = "";
//            while ((line = in.readLine()) != null) {
//                result += line;
//            }
//            return ResultEntity.successWithData(result);
//        } catch (Exception e) {
//            e.printStackTrace();
//            return ResultEntity.failed(e.getMessage());
//        } finally {
//            try {
//                if (in != null) {
//                    in.close();
//                }
//            } catch (Exception e2) {
//                e2.printStackTrace();
//                ResultEntity.failed(e2.getMessage());
//            }
//        }
//    }
//
//    public static String calcAuthorization(String source, String secretId, String secretKey, String datetime)
//            throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException {
//        String signStr = "x-date: " + datetime + "\n" + "x-source: " + source;
//        Mac mac = Mac.getInstance("HmacSHA1");
//        Key sKey = new SecretKeySpec(secretKey.getBytes("UTF-8"), mac.getAlgorithm());
//        mac.init(sKey);
//        byte[] hash = mac.doFinal(signStr.getBytes("UTF-8"));
////        String sig = new BASE64Encoder().encode(hash);
//        String sig = Base64.getEncoder().encodeToString(hash);
//
//        String auth = "hmac id=\"" + secretId + "\", algorithm=\"hmac-sha1\", headers=\"x-date x-source\", signature=\"" + sig + "\"";
//        return auth;
//    }
//
//    public static String urlencode(Map<?, ?> map) throws UnsupportedEncodingException {
//        StringBuilder sb = new StringBuilder();
//        for (Map.Entry<?, ?> entry : map.entrySet()) {
//            if (sb.length() > 0) {
//                sb.append("&");
//            }
//            sb.append(String.format("%s=%s",
//                    URLEncoder.encode(entry.getKey().toString(), "UTF-8"),
//                    URLEncoder.encode(entry.getValue().toString(), "UTF-8")
//            ));
//        }
//        return sb.toString();
//    }

    /**
     * 给远程第三方短信接口发送请求把验证码发送到用户手机上
     *
     * @param host     短信接口调用的URL地址
     * @param path     具体发送短信功能的地址
     * @param method   请求方式
     * @param phoneNum 接收短信的手机号
     * @param appCode  用来调用第三方短信API的AppCode
     * @param sign     签名编号
     * @param skin     模板编号
     * @return 返回调用结果是否成功
     * 成功：返回验证码
     * 失败：返回失败消息
     * 状态码: 200 正常；400 URL无效；401 appCode错误； 403 次数用完； 500 API网管错误
     */
    public static ResultEntity<String> sendCodeByShortMessage(String host, String path, String method, String phoneNum, String appCode, String sign, String skin) {

        Map<String, String> headers = new HashMap<String, String>();

        // 最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appCode);

        // 封装其他参数
        Map<String, String> querys = new HashMap<String, String>();

        // 生成验证码
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            int random = (int) (Math.random() * 10);
            builder.append(random);
        }

        String code = builder.toString();

        // 要发送的验证码，也就是模板中会变化的部分
        querys.put("param", code);

        // 收短信的手机号
        querys.put("phone", phoneNum);

        // 签名编号
        querys.put("sign", sign);

        // 模板编号
        querys.put("skin", skin);
        // JDK 1.8示例代码请在这里下载： http://code.fegine.com/Tools.zip

        try {
            HttpResponse response = HttpUtils.doGet(host, path, method, headers, querys);

            StatusLine statusLine = response.getStatusLine();

            // 状态码: 200 正常；400 URL无效；401 appCode错误； 403 次数用完； 500 API网管错误
            int statusCode = statusLine.getStatusCode();

            String reasonPhrase = statusLine.getReasonPhrase();

            if (statusCode == 200) {

                // 操作成功，把生成的验证码返回
                return ResultEntity.successWithData(code);
            }

            return ResultEntity.failed(reasonPhrase);

        } catch (Exception e) {
            e.printStackTrace();
            return ResultEntity.failed(e.getMessage());
        }

    }

    /**
     * 负责上传文件到OSS服务器的工具方法
     * @param accessKeyId OSS参数
     * @param accessKeySecret OSS参数
     * @param bucketName OSS参数
     * @param bucketDomain OSS参数
     * @param endpoint OSS参数
     * @param originalName 要上传的文件原始文件名
     * @param inputStream 要上传文件的输入流
     * @return 包好上传结果以及上传的文件在OSS上的访问路径
     */
    public static ResultEntity<String> uploadFileToOss(String accessKeyId, String accessKeySecret, String bucketName, String bucketDomain, String endpoint, String originalName, InputStream inputStream) {
        // 1 创建OSSClient实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 2 生成上传文件的目录
        String folderName = new SimpleDateFormat("yyyyMMdd").format(new Date());
        // 3 生成上传文件在OSS服务器上保存时的文件名
        String fileMainName = UUID.randomUUID().toString().replace("-", "");
        // 4 从原始文件名中获取扩展文件扩展名
        String extensionName = originalName.substring(originalName.lastIndexOf("."));
        // 5 使用目录、文件主体名称、文件扩展名称拼接得到对象名称
        String objectName = folderName + "/" + fileMainName + extensionName;
        try {
            // 6 调用OSS客户端对象的方法上传文件并获取响应结果
            PutObjectResult putObjectResult = ossClient.putObject(bucketName, objectName, inputStream);
            // 7 从响应结果中获取具体响应消息
            ResponseMessage responseMessage = putObjectResult.getResponse();
            // 8 根据响应状态码判断请求是否成功
            if (responseMessage == null) {
                // 拼接访问刚刚上传文件的路径
                String ossFileAccessPath = bucketDomain + "/" + objectName;
                // 返回成功
                return ResultEntity.successWithData(ossFileAccessPath);
            } else {
                // 获取响应状态码
                int statusCode = responseMessage.getStatusCode();
                // 获取错误消息
                String errorMessage = responseMessage.getErrorResponseAsString();
                // 返回失败
                return ResultEntity.failed("当前响应状态码：" + statusCode + "错误消息：" + errorMessage);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResultEntity.failed(e.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}
